/*
	Copyright (C) 2010 Tim Beyer
	
    This file is part of Pixelbots.

    Pixelbots is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Pixelbots is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Pixelbots.  If not, see <http://www.gnu.org/licenses/>.
	
*/

function BrightSeeker(brightnessMap,x,y){
			
			    var map = brightnessMap; //The brightness information
			    var x = x;	//current x-coordinate
			    var y = y;	//current y-coordinate
			    var maxX = map.width;	//biggest possible x-coordinate
			    var maxY = map.height;	//biggest possible y-coordinate
				this.drawThreshold = 0.45;	//brightness threshold where to begin drawing the pixels

			    //how fast the seeker death countdown will progress
			    var deathMult = 1;
			    //how fast the seeker reproduction countdown will progress
			    var reproductionMult = 1;
			    
			    var lifeTime = 100;
			    var reproductionTime = 100;
			    
			    var dead = false;
			    
			    this.nextStep = function(){
					if(map.getRelativeBrightness(x,y) < 0.1) dead=true;
					
					if(lifeTime < 0){
						dead = true;
					}
					if(dead){
						return;
						//later remove it from the objects to draw
					}
					
					//set the multipliers
					//make directly proportional to brightness of image
					deathMult = 1-map.getRelativeBrightness(x,y);
					reproductionMult = map.getRelativeBrightness(x,y);
					
					//update lifeTime and reproduction time
					lifeTime -= deathMult;
					reproductionTime -= reproductionMult;
					
					
					var nextCoords = possibleNextCoords(x,y,maxX,maxY);

					
					//find best position
					var bestIndex = 0;
					var best = map.getBrightness(x,y);
					
					for(i = 0; i < nextCoords.length; i++){
						var score = map.getBrightness(nextCoords[i].x,nextCoords[i].y);
						if(score > best){
							bestIndex = i;
							best = score;
						}
					}
					

					
					if(Math.random() > 0.8){
						bestIndex = Math.floor(Math.random() * nextCoords.length);
					}
					//do step
					x = nextCoords[bestIndex].x;
					y = nextCoords[bestIndex].y;
					
					//alert("NextCoord: " + x + " " + y);
			    
			    }
			    

			    
			    
			    this.getPosition = function(){
				var pos = {"x": x, "y":y};
				return pos;
			    }
			    
			    this.getCurrentBrightness = function(){
					return map.getBrightness(x,y);
			    }
				
				this.getRelativeBrightness = function(){
					return map.getRelativeBrightness(x,y);
				}
				
				this.draw = function(pixelImage){
						var bright = this.getRelativeBrightness();
						if(bright > this.drawThreshold){
							var pixel = new Pixel(255,255,255,255);
							pixelImage.putPixel(pixel,x,y);
						}
				}
}

function BrightBreeder(brightnessMap,x,y){

	//create position map
	var positionMap = new PositionMap(brightnessMap.width,brightnessMap.height);
	var brightnessMap = brightnessMap;
	//the array that holds all the agents spawned by this Mycelium
	var subAgents = new Array();
	var toBeAdded = new Array();
	var numberSubAgents = 1;
	
	//add first agent
	subAgents.push(new SubAgent(x,y));
	//add a few randomly distributed agents that share the same position map
	for(var i = 0; i < 500; i++){
		subAgents.push(new SubAgent(random(brightnessMap.width),random(brightnessMap.height)));
	}
	//just delegate the task to the subagents
	this.nextStep = function(){
		if(subAgents.length == 0){
			//dead
			return;
		}
		//remove the agents that died last round
		removeDeadAgents();
		addAgents();
		for(var agent = 0; agent < subAgents.length; agent++){
			subAgents[agent].nextStep();
		}
	}

	//and let the subagents do that as well
	this.draw = function(pixelImage){
		if(subAgents.length == 0){
			//dead
			return;
		}
		for(var i = 0; i < subAgents.length; i++){
			subAgents[i].draw(pixelImage);
		}
	}
	
	function removeDeadAgents(){
		var remainingAgents = new Array();
		var totalAlive = 0;
		for(var i = 0; i < subAgents.length; i++){
			if(subAgents[i].isAlive()) remainingAgents.push(subAgents[i]);
			totalAlive++;
		}
		subAgents = remainingAgents;
	}
	
	function scheduleAdd(subAgent){
		toBeAdded.push(subAgent);
	}
	
	function addAgents(){
		for(var i = 0; i < toBeAdded.length; i++){
			subAgents.push(toBeAdded[i]);
		}
		toBeAdded = new Array();
	}
	 
	function SubAgent(x,y){

		var x = x;
		var y = y;
		
		this.maxHealth = 300; //the starting health of the agent
		var health = this.maxHealth; //the health of the agent, decreases over time. the agent is removed when health has reached 0
		var alive = true; //the agent is still alive
		
		this.reproCountdownStart = 100; //the starting reproduction countdown
		var reproCountdown = this.reproCountdownStart; //when this hits 0, the agent reproduces
		
		
		var direction = {"x":1,"y":1}; //the direction to go 

		this.nextStep = function(){
			var nextCoords = positionMap.possibleNextCoords(x,y);
			//die and return if no coord possible
			if(nextCoords.length == 0 || health <= 0){
				this.alive = false;
				return;
			}
			
			if(reproCountdown <= 0){
				scheduleAdd(new SubAgent(x,y));
				reproCountdown = this.reproCountdownStart;
			}
		
			//find best position
			var bestIndex = 0;
			var best = brightnessMap.getBrightness(x,y);
			
			for(i = 0; i < nextCoords.length; i++){
				var score = brightnessMap.getBrightness(nextCoords[i].x,nextCoords[i].y);
				if(score > best){
					bestIndex = i;
					best = score;
				}
			}
			

			
			if(Math.random() > 0.8){
				bestIndex = Math.floor(Math.random() * nextCoords.length);
			}
			//do step
			x = nextCoords[bestIndex].x;
			y = nextCoords[bestIndex].y;					

				
			positionMap.markVisited(x,y);
			var brightness = brightnessMap.getRelativeBrightness(x,y);
			reproCountdown -= brightness * 10;
			if(brightness > 0.9){
				//this is good, let's take even less health
				health -= (1 - brightness) * 5;
			}
			health -= (1 - brightness) * 10;

			
		}
		

		this.draw = function(pixelImage){
			var brightness = brightnessMap.getBrightness(x,y);
			var pixel = new Pixel(255,255,255,255);
			pixelImage.putPixel(pixel,x,y);
		}
		
		this.isAlive = function(){
			return alive;
		}
	
	}

}

function RandomGrowth(brightnessMap,x,y){

	//create position map
	var positionMap = new PositionMap(brightnessMap.width,brightnessMap.height);
	var brightnessMap = brightnessMap;
	//the array that holds all the agents spawned by this Mycelium
	var subAgents = new Array();
	var toBeAdded = new Array();
	var numberSubAgents = 1;
	
	//add first agent
	subAgents.push(new SubAgent(x,y));
	
	//just delegate the task to the subagents
	this.nextStep = function(){
		if(subAgents.length == 0){
			//dead
			return;
		}
		//remove the agents that died last round
		removeDeadAgents();
		addAgents();
		for(var agent = 0; agent < subAgents.length; agent++){
			subAgents[agent].nextStep();
		}
	}

	//and let the subagents do that as well
	this.draw = function(pixelImage){
		if(subAgents.length == 0){
			//dead
			return;
		}
		for(var i = 0; i < subAgents.length; i++){
			subAgents[i].draw(pixelImage);
		}
	}
	
	function removeDeadAgents(){
		var remainingAgents = new Array();
		var totalAlive = 0;
		for(var i = 0; i < subAgents.length; i++){
			if(subAgents[i].isAlive()) remainingAgents.push(subAgents[i]);
			totalAlive++;
		}
		subAgents = remainingAgents;
	}
	
	function scheduleAdd(subAgent){
		toBeAdded.push(subAgent);
	}
	
	function addAgents(){
		for(var i = 0; i < toBeAdded.length; i++){
			subAgents.push(toBeAdded[i]);
		}
		toBeAdded = new Array();
	}
	 
	function SubAgent(x,y){

		var x = x;
		var y = y;
		
		this.maxHealth = 100; //the starting health of the agent
		var health = this.maxHealth; //the health of the agent, decreases over time. the agent is removed when health has reached 0
		var alive = true; //the agent is still alive
		
		this.reproCountdownStart = 15; //the starting reproduction countdown
		var reproCountdown = this.reproCountdownStart; //when this hits 0, the agent reproduces
		
		
		var direction = {"x":1,"y":1}; //the direction to go 

		this.nextStep = function(){
			var possibleNextCoords = positionMap.possibleNextCoords(x,y);
			//die and return if no coord possible
			if(possibleNextCoords.length == 0){
				this.alive = false;
				return;
			}
			
			if(reproCountdown == 0){
				scheduleAdd(new SubAgent(x,y));
				reproCountdown = this.reproCountdownStart;
			}
		
			var randomIndex = random(possibleNextCoords.length);
			var chosenCoord = possibleNextCoords[randomIndex];
					
			x = chosenCoord.x;
			y = chosenCoord.y;
				
			positionMap.markVisited(x,y);
			reproCountdown--;
			health--;

			
		}
		

		this.draw = function(pixelImage){
			var brightness = brightnessMap.getBrightness(x,y);
			var pixel = new Pixel(brightness,brightness,brightness,255);
			pixelImage.putPixel(pixel,x,y);
		}
		
		this.isAlive = function(){
			return alive;
		}
	
	}

}

//A boolean array to store the information about where an agent has already been
function PositionMap(width,height){

	var map = new Array(); //the boolean array. true = visited, false = visited
	this.width = width;
	this.height = height;
	initialize();
	
	function initialize(){
		for(i = 0; i < width*height; i++)
			map.push(false);
	}
	function getIndex(x,y){
	    return (y*this.width + x);
	}
	
	this.markVisited = function(x,y){
		map[getIndex(x,y)] = true;
	}
	
	this.wasVisited = function(x,y){
	    return map[getIndex(x,y)];
	}
	
	this.possibleNextCoords = function(x,y){
		var allCoords = possibleNextCoords(x,y,this.width,this.height);
		var remainingCoords = new Array();
		for(i = 0; i < allCoords.length; i++){
			coord = allCoords[i];
			if(!this.wasVisited(coord.x,coord.y)){
				remainingCoords.push(coord);
			}
		}
		return remainingCoords;
	}
}

function possibleNextCoords(x,y,width,height){
	var nextCoords = new Array();

	if(y>0){
		//down
		nextCoords.push({"x":x, "y":y-1});
	}

	if(y<height){
		//up
		nextCoords.push({"x":x, "y":y+1});
	}

	if(x > 0){
		//Left
		nextCoords.push({"x":x-1, "y":y});
		if(y > 0){
		//downLeft
		nextCoords.push({"x":x-1, "y":y-1});
		}
		if(y < height){
		//leftUp
		nextCoords.push({"x":x-1, "y":y+1});

		}
	}
	if(x < width){
		//Right
		nextCoords.push({"x":x+1, "y":y});
		if(y > 0){
		//upRight
		nextCoords.push({"x":x+1, "y":y+1});
		}
		if(y < width){
		//rightDown
		nextCoords.push({"x":x+1, "y":y-1});
		}
	}
	return nextCoords;
}